import { Context } from './context';
import { Module, ModuleType } from './module';
import { Dependency } from './moduleGraph';
import { Ast } from '../types';

export interface PluginLoadResult {
  content: string;
  moduleType: ModuleType;
}

export interface Plugin {
  name: string;

  load?(context: Context, moduleId: string): PluginLoadResult | undefined;

  parse?(context: Context, moduleId: string, moduleType: ModuleType, content: string): Ast | undefined;

  analyzeDeps?(context: Context, module: Module): Dependency[] | undefined;

  generateStart?(context: Context): void;

  transform?(context: Context, module: Module): void;

  generateEnd?(context: Context): void | Promise<void>;
}

export class PluginDriver {
  plugins: Plugin[];

  constructor(plugins: Plugin[]) {
    this.plugins = plugins;
  }

  load(context: Context, moduleId: string) {
    for (const plugin of this.plugins) {
      const result = plugin.load?.(context, moduleId);
      if (result) {
        return result;
      }
    }
    return undefined;
  }

  parse(context: Context, moduleId: string, moduleType: ModuleType, content: string) {
    for (const plugin of this.plugins) {
      const result = plugin.parse?.(context, moduleId, moduleType, content);
      if (result) {
        return result;
      }
    }
    return undefined;
  }

  analyzeDeps(context: Context, module: Module) {
    for (const plugin of this.plugins) {
      const result = plugin.analyzeDeps?.(context, module);
      if (result) {
        return result;
      }
    }
    return undefined;
  }

  generateStart(context: Context) {
    for (const plugin of this.plugins) {
      plugin.generateStart?.(context);
    }
  }

  transform(context: Context, module: Module) {
    for (const plugin of this.plugins) {
      plugin.transform?.(context, module);
    }
  }

  async generateEnd(context: Context) {
    for (const plugin of this.plugins) {
      await plugin.generateEnd?.(context);
    }
  }
}
